/**
 * Created by Administrator on 2017/2/17 0017.
 */
//定义一个定时器,用来接受设置的定时器
var timer;
//这几个函数是在公开函数的方法,为静态成员
//选择器方法,返回的是document.querySelectorAll返回值
$.select = function (selector) {
    return document.querySelectorAll(selector);
}
//判断传入的对象是不是数组或者伪数组,即能不能用for循环遍历
$.isArrayLike = function (obj) {
    //obj借用toString方法,返回的是[object obj类型]
    if (toString.call(obj).slice(8, -1) === "Array") {
        return true;
    }
    //如果obj有length属性返回属性值,没有的话length为false
    var length = 'length' in obj && obj.length;
    return typeof length === "number" && length >= 0;
}
$.each = function (obj, callback) {
    //如果isArrayLike为TRUE,for循环遍历
    if ($.isArrayLike(obj)) {
        for (var i = 0; i < obj.length; i++) {
            /*call后面的第一个参数改变this指向,实现each遍历时this可以代表当前遍历对象
             如果返回值是false的话,就跳出循环
             */
            if (callback.call(obj[i], i, obj[i]) === false) break;
        }
    } else {
        for (var k in obj) {
            /*call后面的第一个参数改变this指向,实现each遍历时this可以代表当前遍历对象
             如果返回值是false的话,就跳出循环
             */
            if (callback.call(obj[k], k, obj[k]) === false) break;
        }
    }
    //实现链式编程
    return this;
}
$.map = function (obj, callback) {
    //map方法遍历返回的是一个数组,创建一个新数组用来接收数据
    var arr = [], tmp;
    //如果isArrayLike为TRUE,for循环遍历
    if ($.isArrayLike(obj)) {
        for (var i = 0; i < obj.length; i++) {
            tmp = callback(obj[i], i);
            //如果回调函数的返回值不为null,数组就接受这个数据,包括undefined
            if (tmp !== null) {
                arr.push(tmp)
            }
        }
    } else {
        for (var k = 0; k < obj.length; k++) {
            tmp = callback(obj[k], k);
        }
        //如果回调函数的返回值不为null,数组就接受这个数据,包括undefined
        if (tmp !== null) {
            arr.push(tmp)
        }
    }
    //返回这个数组
    return arr;
}
//如果传入的是html字符串,创建一个div用来接收传入的字符串
$.parseHTML = function (str) {
    var div = document.createElement("div");
    div.innerHTML = str;
    //返回这个div的子节点,可以得到传入html字符串对应的标签
    //return div.childNodes;
    var tmp=[];
    $.each(div.childNodes, function (i, v) {
        tmp.push(v);
    })
    return tmp;
}
//创建对外公开函数,返回值是构造函数创建出来的实例
function $(selector) {
    return new $.prototype.init(selector);
}
$.prototype = {
    constructor: $,
    length: 0,
    //init是构造函数,每次创建出来一个实例对象即为选择器返回的值
    init: function (selector) {
        // 传入的如果是 0, '', nulll, undefined
        if (!selector) return this;
        //判断传入的是不是html字符串,如果是html字符串,则向构造函数的实例中添加parseHTML方法的返回值
        if (/^\s*</.test(selector)) {
            [].push.apply(this, $.parseHTML(selector))
        } else {
            //如果传入的是选择器,则向构造函数的实例中添加select方法的返回值
            [].push.apply(this, $.select(selector));
        }
    }
}
//对外公开的函数和构造函数共享一个原型,这样在给对外公开函数原型添加方法的时候,构造函数也可以访问这个方法,实现添加即可用
$.prototype.init.prototype = $.prototype;
//给静态成员和原型是同时添加扩展方法的方法
$.extend = $.prototype.extend = function (obj) {
    for (var k in obj) {
        this[k] = obj[k];
    }
    //实现链式编程
    return this;
}
//给原型添加方法,即添加实例成员
$.prototype.extend({
    each: function (callback) {
        return $.each(this, callback);
    },
    map: function (callback) {
        return $.map(this, callback);
    },
    //转换成数组的方法
    toArray: function () {
        //slice是截取数组,如果不传参数则是从第一项到最后一项返回一个新的数组
        return [].slice.call(this);
        //或是利用map方法返回一个新数组的特性进行遍历
        /*    return  $.map(this, function (v, i) {
         return v;
         })
         */
    },
    //利用get方法获取的是标准dom元素
    get: function (n) {
        //如果不传参数,那么就执行toArray方法
        if (n === undefined) {
            return this.toArray()
        }
        ;
        //如果传入的参数小于0,则时从后面获取,length+n恰是要获取的元素
        if (n < 0) {
            return this[this.length + n];
        } else {
            return this[n];
        }
    },
    //eq方法同get方法类似,不过获取的不是dom元素
    eq: function (n) {
        //如果不传参数,那么就执行toArray方法
        if (n == undefined) {
            return this.constructor();
        }
        ;
        //利用构造函数不传参数获取一个空的对象
        var obj = this.constructor();
        //obj借用数组的push方法,将第n项添加到空对象当中
        if (this.get(n)) {
            [].push.call(obj, this.get(n));
        }

        //返回这个对象
        return obj;
    },
    first: function () {
        //利用构造函数不传参数获取一个空的对象
        var obj = this.constructor();
        //obj借用数组的push方法,将第0项添加到空对象当中
        [].push.call(obj, this.get(0));
        //返回这个对象
        return obj;

        //或是直接用eq方法
        // return this.eq(0);
    },
    last: function () {
        //利用构造函数不传参数获取一个空的对象
        var obj = this.constructor();
        //obj借用数组的push方法,将最末项添加到空对象当中
        [].push.call(obj, this.get(-1));
        //返回这个对象
        return obj;
        //或是直接用eq方法
        //return this.eq(-1);
    },
    //设置样式方法
    css: function (obj) {
        //采用each方法遍历当前对象,给每个对象都添加样式
        $.each(this, function (i, v) {
            //对传入的对象遍历,把每个属性都添加上
            for (var k in obj) {
                v.style[k] = obj[k];
            }
        })
        //返回this,实现链式编程
        return this;
    },
    //类似jq的颜色渐变的动画,逐渐出现
    fadeIn: function () {
        //定义一个初始值
        var opacity = 0;
        //定义一个变量接收this
        var thi = this;
        if (timer) {
            // alert(1);
            clearInterval(timer);
        }
        //设置定时器,用来逐渐改变透明度
        timer = setInterval(function () {
            //每次增加opacity值,增加透明度
            opacity++;
            //用each方法遍历this,给每一项都设置
            $.each(thi, function (i, v) {
                v.style.opacity = opacity / 100;

            });
            //当透明度达到1时,清除定时器
            if (opacity == 100) {
                clearInterval(timer);
            }
        }, 20)
        //实现链式编程
        return this;
    },
    fadeOut: function () {
        //clearInterval(thi.timer);
        //定义一个初始值
        if (timer) {
            clearInterval(timer);
        }
        var opacity = 100;
        //定义一个变量接收this
        var thi = this;
        //设置定时器
        timer = setInterval(function () {
            opacity--;
            //用each方法遍历this,给每一项都设置
            $.each(thi, function (i, v) {
                v.style.opacity = opacity / 100;
            })
            //当透明度降到0时,清除定时器
            if (opacity == 0) {
                clearInterval(timer);
            }
        }, 20)
    },
    //添加逐渐消失动画的方法
    hide: function (time, callback) {
        //当没有传时间函数的时候,给time一个默认的值
        if (!time || typeof time != "number") {
            time = 600;
        }
        //定义变量接收this
        var thi = this;
        // var i=0;
        //宽高渐变,设置变量每次的新的宽高给元素设置
        var newWidth, newHeight;
        //添加定时器
        timer = setInterval(function () {
            //  i++;
            //遍历this,给每一个都设置
            $.each(thi, function (i, v) {
                //获取初始宽高
                var width = this.offsetWidth;
                var height = this.offsetHeight;
                //给新的宽高赋值,每次改变的量为width*(20/time),当最后值不足再减一次的时候,直接赋值为0
                newWidth = width - width * (20 / time) < width * (20 / time) ? 0 : parseInt(width - width * (20 / time));
                newHeight = height - height * (20 / time) < height * (20 / time) ? 0 : parseInt(height - height * (20 / time));
                this.style.width = newWidth + "px";
                this.style.height = newHeight + "px";
            })
            //当元素的宽高都是0的时候,清除定时器,然后调用回调函数
            if (newWidth == 0 && newHeight == 0) {
                //清除定时器
                clearInterval(timer);
                //当没有传入回调函数的时候不调用,传入回调函数就调用
                callback && callback();
            }
        }, 20);
        //实现链式编程
        return this;
    },
    //把当前对象或元素追加到目标中
    appendTo: function (obj) {
        //var thi=this;
        //$.each(obj, function (i, v) {
        //    var value=v;
        //    thi.each(function (i, v) {
        //        value.appendChild(v);
        //    })
        //})
        //定义一个空数组,用来接收每次添加的元素
        var tmp = [];
        //定义一个变量接收this
        var thi=this;
        //对当前对象进行遍历,每一项都添加到目标对象中
        this.each(function (i, v) {
            //定义一个变量用于接收当前遍历的值
            var value = v;
            //定义一个变量接收当前索引
            var index=i;
            //对目标对象进行遍历,让目标对象的每一项都被添加元素
            $.each(obj, function (i, v) {
                //if(i!=obj.length-1){
                //    var val=value.cloneNode(true);
                //    v.appendChild(val);
                //}else{
                //    v.appendChild(value);
                //}
                //append具有剪切性,所以前面所有项没用克隆的节点添加,第length-1项即最后一项不再克隆
                //当目标对象和当前对象都是最后一项的时候才不克隆
                var val = i == obj.length - 1 && index==thi.length-1 ? value : value.cloneNode(true);
                v.appendChild(val);
                //把添加的元素追加到数组中
                tmp.push(val)
            })
        })
        //创建一个空的$对象
        var obj = this.constructor();
        // 把这个数组追加到这个$对象中
        [].push.apply(obj, tmp);
        //返回$对象,实现链式编程
        return obj;
    },
    //给当前对象添加元素
    append: function (obj) {
        //遍历当前对象的每一项,给每一项都添加
        var thi=this;

        this.each(function (i, v) {
            //定义一个变量接收当前遍历项的值
            var value = v;
            var index=i;
            //遍历要被添加的对象,使目标对象的每一项都被添加
            $.each(obj, function (i, v) {
                //if(i!=obj.length-1 &&index!=this.length-1 ){
                // var val= v.cloneNode(true);
                // //value.appendChild(val);
                // }else{
                // //value.appendChild(v);
                //    val=v;
                // }
                // append具有剪切性,所以前面所有项没用克隆的节点添加,第length-1项即最后一项不再克隆
                var val = i == obj.length - 1 &&index==thi.length-1? v : v.cloneNode(true);
                //给value即this的每一项添加目标元素
                value.appendChild(val);
            })
        })
        //返回this,实现链式编程
        return this;
    },
    //获取相邻的下一个元素的方法
    next: function () {
        //定义一个空对象用来接收当前对象的每一项的下一项
        var tmp=[];
        //创建一个空的$对象
        var obj=this.constructor();
        //对当前对象遍历,得到每一项的下一个
        this.each(function (i, v) {
            //把每一项的相邻元素添加到数组中
            tmp.push(v.nextElementSibling);
        });
        //$对象obj借用push方法把数组tmp追加到自身
        [].push.apply(obj,tmp);
        //返回这个$对象obj
        return obj;
    },
    prev:function(){
        //定义一个空对象用来接收当前对象的每一项的上一项
        var tmp=[];
        //创建一个空的$对象
        var obj=this.constructor();
        //对当前对象遍历,得到每一项的下一个
        this.each(function (i, v) {
            //把每一项的相邻上一个元素添加到数组中
            tmp.push(v.previousElementSibling);
        });
        //$对象obj借用push方法把数组tmp追加到自身
        [].push.apply(obj,tmp);
        //返回这个$对象obj
        return obj;
    },
    insertBefore: function (obj) {

    }
})
















